package xyz.lwm.lazycat.utility.reflect;

import org.jetbrains.annotations.NotNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author lwm
 */
class AnnotationsImpl implements Annotations {

    private final Map<Class<? extends Annotation>, Annotation> annotations = new LinkedHashMap<>();

    public AnnotationsImpl(AnnotatedElement... elements) {
        // add to annotations
        for (AnnotatedElement element : elements) {
            putAnnotations(element);
        }
        // handle alias
        handleAlias();
    }

    @Override
    public <T extends Annotation> boolean hasAnnotation(@NotNull Class<T> annotationType) {
        return annotations.containsKey(annotationType);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Annotation> T getAnnotation(@NotNull Class<T> annotationClass) {
        return (T) annotations.get(annotationClass);
    }

    @NotNull
    @Override
    public Annotation[] getAnnotations() {
        return annotations.values().toArray(new Annotation[0]);
    }

    @NotNull
    @Override
    public Annotation[] getDeclaredAnnotations() {
        return getAnnotations();
    }

    @Override
    public void addAnnotations(@NotNull AnnotatedElement element) {
        putAnnotations(element);
        handleAlias();
    }

    // put annotations
    private void putAnnotations(@NotNull AnnotatedElement element) {
        for (Annotation annotation : element.getAnnotations()) {
            if (!AnnotationUtil.isMetaAnnotation(annotation.annotationType())) {
                annotations.put(annotation.annotationType(), annotation);
                putAnnotations(annotation.annotationType());
            }
        }
    }

    // handle alias to
    private void handleAlias() {
        annotations.values().forEach(a ->
                new AliasHandler(a, this).handle());
    }

}
